{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "4a87f55f-9cb5-4aee-8d80-cd3b7935aa2d",
   "metadata": {},
   "source": [
    "# Strands Agents with AgentCore Memory (Long term memory via Tool)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "295730ce-6bc3-40bf-94bc-c534fd6a950d",
   "metadata": {},
   "source": [
    "## Introduction\n",
    "\n",
    "This notebook demonstrates how to implement a **multi-agent system with shared long-term memory** using AgentCore Memory and the Strands framework. We will explore how multiple specialized agents can work together while accessing a common long-term memory store with dedicated namespaces for each agent.\n",
    "\n",
    "### Tutorial Details\n",
    "\n",
    "| Information         | Details                                                                          |\n",
    "|:--------------------|:---------------------------------------------------------------------------------|\n",
    "| Tutorial type       | Long term Conversational                                                         |\n",
    "| Agent type          | Travel Booking Assistant                                                         |\n",
    "| Agentic Framework   | Strands Agents                                                                   |\n",
    "| LLM model           | Anthropic Claude Sonnet 3.7                                                      |\n",
    "| Tutorial components | AgentCore User Preferences Memory Extraction, Tool for storing and retrieving Memory              |\n",
    "| Example complexity  | Intermediate                                                                     |\n",
    "\n",
    "You will learn:\n",
    "\n",
    "- How to set up a shared memory resource with a long-term memory strategy\n",
    "- Creating specialized agents with access to their own memory namespaces\n",
    "- Implementing a coordinator agent that delegates to specialized agents\n",
    "- Leveraging structured memory namespaces for agent specialization\n",
    "\n",
    "## Scenario context\n",
    "\n",
    "In this example, we'll create a **Travel Planning System** with:\n",
    "1. A Flight Booking Assistant with long-term memory of travel preferences and history\n",
    "2. A Hotel Booking Assistant with long-term memory of accommodation preferences\n",
    "3. A Travel Coordinator that orchestrates these specialized agents\n",
    "\n",
    "Each specialized agent will access its own namespace within a common memory store, enabling them to build persistent understanding of user preferences over time. This approach demonstrates how complex domains can be broken down into specialized agents that share a memory infrastructure but maintain their own areas of expertise.\n",
    "\n",
    "## Architecture\n",
    "<div style=\"text-align:left\">\n",
    "    <img src=\"architecture.png\" width=\"65%\" />\n",
    "</div>\n",
    "\n",
    "## Prerequisites\n",
    "\n",
    "To execute this tutorial you will need:\n",
    "- Python 3.10+\n",
    "- AWS credentials with Amazon Bedrock AgentCore Memory permissions\n",
    "- Amazon Bedrock AgentCore SDK\n",
    "\n",
    "Let's get started by setting up our environment and creating our shared long-term memory resource!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a9f2653-69ca-4241-95b1-063085edf695",
   "metadata": {},
   "source": [
    "## Step 1: Environment set up\n",
    "Let's begin importing all the necessary libraries and defining the clients to make this notebook work."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0ea35f65-29ba-42e7-a756-7ab5b93a84ce",
   "metadata": {},
   "outputs": [],
   "source": [
    "!pip install -qr requirements.txt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f63a5236-2e64-4029-876c-87fe808ce0a8",
   "metadata": {},
   "outputs": [],
   "source": [
    "import logging\n",
    "import time\n",
    "from datetime import datetime\n",
    "from strands.hooks import AfterInvocationEvent, HookProvider, HookRegistry\n",
    "\n",
    "logging.basicConfig(level=logging.INFO, format=\"%(asctime)s - %(levelname)s - %(message)s\", datefmt=\"%Y-%m-%d %H:%M:%S\")\n",
    "logger = logging.getLogger(\"travel-assistant\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "acb536ec-494a-45e5-b425-aaa2b7f21792",
   "metadata": {},
   "source": [
    "Define the region with the appropiate permissions for Amazon Bedrock models and AgentCore"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "746a9e5c-0893-431a-9585-9e8bfb13fd52",
   "metadata": {},
   "outputs": [],
   "source": [
    "region = \"us-west-2\" # Replace with your AWS region"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ef644e57-9e6f-413d-9b26-5eeb775d7760",
   "metadata": {},
   "source": [
    "## Step 2: Creating Shared Memory Resource\n",
    "In this section, we'll create common long-term memory store with dedicated namespaces for each agent."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "86de86a0-825b-4d4d-8180-3d31c4c1fd94",
   "metadata": {},
   "outputs": [],
   "source": [
    "from bedrock_agentcore.memory import MemoryClient\n",
    "from bedrock_agentcore.memory.constants import StrategyType\n",
    "\n",
    "client = MemoryClient(region_name=region)\n",
    "memory_name = \"TravelAgent_LTM\"\n",
    "memory_id = None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8f32d7a9-dcdd-4296-968c-94aa7f3a7c30",
   "metadata": {},
   "outputs": [],
   "source": [
    "from botocore.exceptions import ClientError\n",
    "\n",
    "try:\n",
    "    print(\"Creating Memory with Long-Term Strategy...\")\n",
    "    # Create the memory resource with a single long-term memory strategy\n",
    "    # The {actorId} placeholder will be dynamically replaced with the actual actor ID\n",
    "    memory = client.create_memory_and_wait(\n",
    "        name=memory_name,\n",
    "        description=\"Travel Agent with Long-Term Memory\",\n",
    "        strategies=[{\n",
    "            StrategyType.USER_PREFERENCE.value: {\n",
    "                \"name\": \"UserPreferences\",\n",
    "                \"description\": \"Captures user preferences\",\n",
    "                \"namespaces\": [\"travel/{actorId}/preferences\"]\n",
    "            }\n",
    "        }],\n",
    "        event_expiry_days=7,  # Short-term conversation expires after 7 days\n",
    "        max_wait=300,\n",
    "        poll_interval=10\n",
    "    )\n",
    "\n",
    "    # Extract and print the memory ID\n",
    "    memory_id = memory['id']\n",
    "    print(f\"Memory created successfully with ID: {memory_id}\")\n",
    "except ClientError as e:\n",
    "    if e.response['Error']['Code'] == 'ValidationException' and \"already exists\" in str(e):\n",
    "        # If memory already exists, retrieve its ID\n",
    "        memories = client.list_memories()\n",
    "        memory_id = next((m['id'] for m in memories if m['id'].startswith(memory_name)), None)\n",
    "        logger.info(f\"Memory already exists. Using existing memory ID: {memory_id}\")\n",
    "except Exception as e:\n",
    "    # Handle any errors during memory creation\n",
    "    logger.info(f\"❌ ERROR: {e}\")\n",
    "    import traceback\n",
    "    traceback.print_exc()\n",
    "    # Cleanup on error - delete the memory if it was partially created\n",
    "    if memory_id:\n",
    "        try:\n",
    "            client.delete_memory_and_wait(memory_id=memory_id)\n",
    "            logger.info(f\"Cleaned up memory: {memory_id}\")\n",
    "        except Exception as cleanup_error:\n",
    "            logger.info(f\"Failed to clean up memory: {cleanup_error}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ac2f225c-5cf5-4f39-a139-4d15e0d1a6e3",
   "metadata": {},
   "source": [
    "### Understanding Long-Term Memory Strategy\n",
    "\n",
    "The memory resource we're creating uses AgentCore Memory's long-term memory capabilities with a single user preference strategy:\n",
    "\n",
    "1. **User Preference Memory Strategy**: Automatically extracts and consolidates user preferences mentioned in conversations\n",
    "2. **Actor-based Namespaces**: Uses the actor ID in the namespace path to create separate spaces for each agent\n",
    "3. **Memory Persistence**: Unlike short-term memory that expires, extracted preferences persist beyond conversation expiry\n",
    "\n",
    "With the namespace pattern `travel/{actorId}/preferences`, each specialized agent will have its own unique namespace based on its actor ID:\n",
    "- Flight agent will access: `travel/flight-user-TIMESTAMP/preferences`\n",
    "- Hotel agent will access: `travel/hotel-user-TIMESTAMP/preferences`\n",
    "\n",
    "This allows each agent to maintain its own specialized knowledge while using a common memory infrastructure.\n",
    "\n",
    "### Setting Up Agent Identities"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5f294943-ff18-420a-b942-dc5f99e0cca5",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create unique actor IDs for each specialized agent but share the session ID\n",
    "flight_actor_id = f\"flight-user-{datetime.now().strftime('%Y%m%d%H%M%S')}\"\n",
    "hotel_actor_id = f\"hotel-user-{datetime.now().strftime('%Y%m%d%H%M%S')}\"\n",
    "session_id = f\"travel-session-{datetime.now().strftime('%Y%m%d%H%M%S')}\"\n",
    "flight_namespace = f\"travel/{flight_actor_id}/preferences\"\n",
    "hotel_namespace = f\"travel/{hotel_actor_id}/preferences\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a288afca-e06e-48b2-b10b-9cb0465c9e23",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import the necessary components\n",
    "from strands import Agent, tool\n",
    "from strands_tools.agent_core_memory import AgentCoreMemoryToolProvider"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "46c590f3-4b1f-452a-946c-709548ce5d33",
   "metadata": {},
   "source": [
    "### Step 3: Create Memory Hook Provider\n",
    "\n",
    "This step defines our custom `MemoryHookProvider` class that automates memory operations. Hooks are special functions that run at specific points in an agent's execution lifecycle. The memory hook we're creating serves one primary function:\n",
    "\n",
    "1. **Save Memories**: Stores new conversations after the agent responds\n",
    "\n",
    "This creates a seamless memory experience without manual management."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e206c1a9-ce22-4a04-9580-e063f62dce56",
   "metadata": {},
   "outputs": [],
   "source": [
    "class MemoryHookProvider(HookProvider):\n",
    "    \"\"\"Hook provider for automatic memory management\"\"\"\n",
    "    \n",
    "    def __init__(self, memory_id: str, client: MemoryClient, actor_id: str, session_id: str):\n",
    "        self.memory_id = memory_id\n",
    "        self.client = client\n",
    "        self.actor_id = actor_id\n",
    "        self.session_id = session_id\n",
    "    \n",
    "    def save_memories(self, event: AfterInvocationEvent):\n",
    "        \"\"\"Save conversation after agent response\"\"\"\n",
    "        try:\n",
    "            messages = event.agent.messages\n",
    "            if len(messages) >= 2:\n",
    "                # Get last user and assistant messages\n",
    "                user_msg = None\n",
    "                assistant_msg = None\n",
    "                \n",
    "                for msg in reversed(messages):\n",
    "                    if msg[\"role\"] == \"assistant\" and not assistant_msg:\n",
    "                        assistant_msg = msg[\"content\"][0][\"text\"]\n",
    "                    elif msg[\"role\"] == \"user\" and not user_msg and \"toolResult\" not in msg[\"content\"][0]:\n",
    "                        user_msg = msg[\"content\"][0][\"text\"]\n",
    "                        break\n",
    "                \n",
    "                if user_msg and assistant_msg:\n",
    "                    # Save conversation\n",
    "                    self.client.create_event(\n",
    "                        memory_id=self.memory_id,\n",
    "                        actor_id=self.actor_id,\n",
    "                        session_id=self.session_id,\n",
    "                        messages=[(user_msg, \"USER\"), (assistant_msg, \"ASSISTANT\")]\n",
    "                    )\n",
    "                    logger.info(\"Saved conversation to memory\")\n",
    "                    \n",
    "        except Exception as e:\n",
    "            logger.error(f\"Failed to save memories: {e}\")\n",
    "    \n",
    "    def register_hooks(self, registry: HookRegistry) -> None:\n",
    "        \"\"\"Register memory hooks\"\"\"\n",
    "        registry.add_callback(AfterInvocationEvent, self.save_memories)\n",
    "        logger.info(\"Memory hooks registered\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "48f39b9d-4238-45e5-a8eb-98a8c450e65a",
   "metadata": {},
   "source": [
    "### Creating Specialized Agents with Memory Access\n",
    "\n",
    "Next, we'll define system prompts for our specialized agents."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bb748408-80cc-4f2a-8950-ed1523bec2aa",
   "metadata": {},
   "outputs": [],
   "source": [
    "# System prompt for the hotel booking specialist\n",
    "HOTEL_BOOKING_PROMPT = f\"\"\"You are a hotel booking assistant. Help customers find hotels, make reservations, and answer questions about accommodations and amenities. \n",
    "Provide clear information about availability, pricing, and booking procedures in a friendly, helpful manner.Ask max two questions per turn. Keep the messages short, don't overwhelm the customer.\"\"\"\n",
    "\n",
    "# System prompt for the flight booking specialist\n",
    "FLIGHT_BOOKING_PROMPT = f\"\"\"You are a flight booking assistant. Help customers find flights, make reservations, and answer questions about airlines, routes, and travel policies. \n",
    "Provide clear information about flight availability, pricing, schedules, and booking procedures in a friendly, helpful manner.Ask max two questions per turn. Keep the messages short, don't overwhelm the customer.\"\"\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a42e6a49-dc31-48ae-b6ca-5e08266fd74a",
   "metadata": {},
   "source": [
    "### Implementing Agent Tools\n",
    "Now we'll implement our specialized agents as tools that can be used by the coordinator agent:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1f67ed8c-c15b-4e5a-a130-aa3ef165fc3f",
   "metadata": {},
   "outputs": [],
   "source": [
    "@tool\n",
    "def flight_booking_assistant(query: str) -> str:\n",
    "    \"\"\"\n",
    "    Process and respond to flight booking queries.\n",
    "\n",
    "    Args:\n",
    "        query: A flight-related question about bookings, schedules, airlines, or travel policies\n",
    "\n",
    "    Returns:\n",
    "        Detailed flight information, booking options, or travel advice\n",
    "    \"\"\"\n",
    "    try:\n",
    "        provider_flight = AgentCoreMemoryToolProvider(\n",
    "            memory_id=memory_id,      # Required\n",
    "            actor_id=flight_actor_id, # Required\n",
    "            session_id=session_id,    # Required\n",
    "            max_results=10,           # Optional\n",
    "            namespace=flight_namespace\n",
    "        )\n",
    "        \n",
    "        flight_memory_hooks = MemoryHookProvider(\n",
    "            memory_id=memory_id,\n",
    "            client=client,\n",
    "            actor_id=flight_actor_id,\n",
    "            session_id=session_id\n",
    "        )\n",
    "\n",
    "        flight_agent = Agent(tools=provider_flight.tools,\n",
    "                             hooks=[flight_memory_hooks],\n",
    "                             system_prompt=FLIGHT_BOOKING_PROMPT\n",
    "                             )\n",
    "\n",
    "        # Call the agent and return its response\n",
    "        response = flight_agent(query)\n",
    "        return str(response)\n",
    "    except Exception as e:\n",
    "        return f\"Error in flight booking assistant: {str(e)}\"\n",
    "\n",
    "@tool\n",
    "def hotel_booking_assistant(query: str) -> str:\n",
    "    \"\"\"\n",
    "    Process and respond to hotel booking queries.\n",
    "\n",
    "    Args:\n",
    "        query: A hotel-related question about accommodations, amenities, or reservations\n",
    "\n",
    "    Returns:\n",
    "        Detailed hotel information, booking options, or accommodation advice\n",
    "    \"\"\"\n",
    "    try:\n",
    "        provider_hotel = AgentCoreMemoryToolProvider(\n",
    "            memory_id=memory_id,      \n",
    "            actor_id=hotel_actor_id, \n",
    "            session_id=session_id,    \n",
    "            max_results=10,           \n",
    "            namespace=hotel_namespace\n",
    "        )\n",
    "\n",
    "        hotel_memory_hooks = MemoryHookProvider(\n",
    "            memory_id=memory_id,\n",
    "            client=client,\n",
    "            actor_id=hotel_actor_id,\n",
    "            session_id=session_id\n",
    "        )\n",
    "\n",
    "        hotel_booking_agent = Agent(tools=provider_hotel.tools, hooks=[hotel_memory_hooks], system_prompt=HOTEL_BOOKING_PROMPT)\n",
    "        \n",
    "        # Call the agent and return its response\n",
    "        response = hotel_booking_agent(query)\n",
    "        return str(response)\n",
    "    except Exception as e:\n",
    "        return f\"Error in hotel booking assistant: {str(e)}\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e7b572d1-d429-4678-a318-2ab153408e23",
   "metadata": {},
   "source": [
    "### Creating the Coordinator Agent\n",
    "\n",
    "Finally, we'll create the main travel planning agent that coordinates between these specialized tools:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4abe237d-36c2-42ab-ae54-4554e1e4f23a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# System prompt for the coordinator agent\n",
    "TRAVEL_AGENT_SYSTEM_PROMPT = \"\"\"\n",
    "You are a comprehensive travel planning assistant that coordinates between specialized tools:\n",
    "- For flight-related queries (bookings, schedules, airlines, routes) → Use the flight_booking_assistant tool\n",
    "- For hotel-related queries (accommodations, amenities, reservations) → Use the hotel_booking_assistant tool\n",
    "- For complete travel packages → Use both tools as needed to provide comprehensive information\n",
    "- For general travel advice or simple travel questions → Answer directly\n",
    "\n",
    "Each agent will have its own memory in case the user asks about historic data.\n",
    "When handling complex travel requests, coordinate information from both tools to create a cohesive travel plan.\n",
    "Provide clear organization when presenting information from multiple sources. \\\n",
    "Ask max two questions per turn. Keep the messages short, don't overwhelm the customer.\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1f10bb9f-031e-49b6-8175-1b676cdd2576",
   "metadata": {},
   "outputs": [],
   "source": [
    "travel_agent = Agent(\n",
    "    system_prompt=TRAVEL_AGENT_SYSTEM_PROMPT,\n",
    "    tools=[flight_booking_assistant, hotel_booking_assistant]\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c361c59d-e322-47ae-92a8-ee6cd994df22",
   "metadata": {},
   "source": [
    "## Testing the Multi-Agent Memory System\n",
    "\n",
    "Let's test our multi-agent system with a travel planning scenario:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a085bace-f5af-40d4-a20c-6e64bc00a3fa",
   "metadata": {},
   "source": [
    "### Optional: Hydrate the long term memory of the flight booking assistant\n",
    "Uncomment the following cell if you want to hydrate the flight booking agent."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6944d10a-3651-4ce0-aee7-8ac551733a47",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"flight_previous_messages = [\n",
    "    (\"Hi, I'm Sarah\", \"USER\"),\n",
    "    (\"Hello Sarah! Welcome to FlightAssist. How can I help you with your travel plans today?\", \"ASSISTANT\"),\n",
    "    (\"I'm looking to book a flight from New York to London sometime next month.\", \"USER\"),\n",
    "    (\"I'd be happy to help you find flights from New York to London for next month. Do you have specific dates in mind, or are you flexible?\", \"ASSISTANT\"),\n",
    "    (\"I'm thinking around the 15th to the 25th, but I can be a bit flexible.\", \"USER\"),\n",
    "    (\"Great! That gives us some room to find the best options. Do you have any preferences regarding airlines or flight times?\", \"ASSISTANT\"),\n",
    "    (\"I definitely prefer direct flights if possible. I really don't like layovers.\", \"USER\"),\n",
    "    (\"I completely understand your preference for direct flights. Layovers can be inconvenient. Fortunately, there are several airlines offering direct flights between New York and London, including British Airways, American Airlines, Delta, and Virgin Atlantic.\", \"ASSISTANT\"),\n",
    "    (\"That's good to hear. I've had good experiences with British Airways in the past.\", \"USER\"),\n",
    "    (\"British Airways does offer excellent service on transatlantic routes. I'll keep that in mind when searching for options. Do you have any seating preferences or other requirements for your flight?\", \"ASSISTANT\"),\n",
    "    (\"I always try to get an aisle seat. I like being able to get up without disturbing others, especially on long flights.\", \"USER\"),\n",
    "    (\"An aisle seat is a great choice for long-haul flights like New York to London. I'll note your preference for aisle seating. Would you prefer to fly in the morning, afternoon, or evening?\", \"ASSISTANT\"),\n",
    "    (\"I prefer overnight flights for long journeys. It helps me adjust to the time difference better.\", \"USER\"),\n",
    "    (\"Overnight flights are indeed a smart choice for eastbound transatlantic travel. They allow you to arrive in London in the morning and help minimize jet lag. British Airways, Delta, and American all offer evening departures from New York that arrive in London the next morning.\", \"ASSISTANT\"),\n",
    "    (\"Perfect! And I'm also wondering about baggage allowances since I'll be staying for about a week.\", \"USER\"),\n",
    "    (\"For a week-long trip, most travelers find that a standard checked bag plus a carry-on is sufficient. British Airways typically allows one free checked bag on transatlantic flights in economy class, plus a carry-on and personal item. Would you like me to check the specific allowances for your preferred dates?\", \"ASSISTANT\")\n",
    "]\n",
    "\n",
    "print(\"\\nHydrating memories with previous conversations...\")\n",
    "\n",
    "# Save the conversation history to short-term memory\n",
    "initial = client.create_event(\n",
    "    memory_id=memory_id,\n",
    "    actor_id=flight_actor_id,\n",
    "    session_id=session_id,\n",
    "    messages=flight_previous_messages,\n",
    ")\n",
    "print(\"✓ Conversation saved in short term memory\")\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8b13aa5d-4abc-41eb-916b-35ccf0b5ab03",
   "metadata": {},
   "outputs": [],
   "source": [
    "travel_agent(\"Hello, I would like to book a trip from LA to Madrid. From July 1 to August 2.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ec209fa8-fd5a-41a8-b7d1-86a1f137331f",
   "metadata": {},
   "outputs": [],
   "source": [
    "travel_agent(\"I prefer direct flights with Iberia\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7085390d-90a7-483e-a3c4-dbffe5d89a49",
   "metadata": {},
   "outputs": [],
   "source": [
    "travel_agent(\"I would like a flight in the morning, in economy\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ceb0e6b8-028e-4f89-8672-6b5e4b2673ca",
   "metadata": {},
   "outputs": [],
   "source": [
    "travel_agent(\"I would like to fly from SNA, and return 15 days later\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ef1ed3c9-93ee-4617-81a7-b462133f4488",
   "metadata": {},
   "source": [
    "## Testing Memory Persistence\n",
    "\n",
    "To test if our memory system is working correctly, we'll create a new instance of the travel agent and see if it can access the previously stored information:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8007b15a-2b00-4f07-aa7d-dfa8ba7b5b10",
   "metadata": {},
   "outputs": [],
   "source": [
    "time.sleep(60) # Let's give the memory some time to process the events..\n",
    "# Create a new instance of the travel agent\n",
    "new_travel_agent = Agent(\n",
    "    system_prompt=TRAVEL_AGENT_SYSTEM_PROMPT,\n",
    "    tools=[flight_booking_assistant, hotel_booking_assistant]\n",
    ")\n",
    "\n",
    "# Ask about previous conversations\n",
    "new_travel_agent(\"Can you remind me about flight preferences?\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2fb6cdd1-5c11-4346-9c5a-93fb44c779ac",
   "metadata": {},
   "source": [
    "## Summary\n",
    "\n",
    "In this notebook, we've demonstrated:\n",
    "\n",
    "1. How to create a shared memory resource for multiple agents\n",
    "2. How to implement specialized agents as tools with memory access\n",
    "3. How to coordinate between multiple agents while maintaining conversation context\n",
    "4. How memory persists across different agent instances\n",
    "\n",
    "This multi-agent architecture with shared memory provides a powerful approach for building complex conversational AI systems that can handle specialized domains while maintaining a cohesive user experience."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "18852f04-e06e-4787-9c4f-3d2d2ba8563b",
   "metadata": {},
   "source": [
    "## Clean up\n",
    "Let's delete the memory to clean up the resources used in this notebook."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3d4577ee-3a79-4a44-abde-86391e98e4bb",
   "metadata": {},
   "outputs": [],
   "source": [
    "# client.delete_memory_and_wait(\n",
    "#        memory_id = memory_id,\n",
    "#        max_wait = 300,\n",
    "#        poll_interval =10\n",
    "#)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "conda_python3",
   "language": "python",
   "name": "conda_python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
